package com.asdhawaii.otello;

import com.asdhawaii.otello.players.PlayerType;
import com.asdhawaii.otello.util.ImageLoader;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Font;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;

/**
 * The panel containing information about the current round and play.
 * 
 * @author Branden Ogata
 *
 */

@SuppressWarnings("serial")
public class StatsPanel extends JPanel
{
  /**
   * The Container in which this StatsPanel is located.
   * 
   */
  private Container parent;
  
  /**
   * The table of statistics.
   * 
   */
  private JTable statsTable;
  
  /**
   * The model of the statistics table.
   * 
   */
  private OtelloTableModel statsTableModel;
  
  /**
   * Creates a new StatsPanel.
   * 
   * @param parent The Container in which the new StatsPanel is located.
   * 
   */
  
  public StatsPanel(Container parent)
  {
    this.setLayout(new BorderLayout());
    
    this.parent = parent;
    
    // Use the values in the parent if the parent is an OtelloPanel;
    // else the default values are set up for our client and primary (only) developer;
    if (this.parent instanceof OtelloPanel)
    {
      OtelloPanel valueSource = (OtelloPanel) this.parent;
      this.statsTableModel = new OtelloTableModel(valueSource.getPlayerZeroType(), 
                                                  valueSource.getPlayerZeroName(),
                                                  valueSource.getPlayerOneType(), 
                                                  valueSource.getPlayerOneName());
    }
    else
    {
      this.statsTableModel = new OtelloTableModel(PlayerType.GIRL, "Christine",
                                                  PlayerType.BOY, "Branden");      
    }
    this.statsTable = new JTable(this.statsTableModel);
    this.statsTable.setRowHeight(128);
    this.statsTable.setFont(new Font(Font.SERIF, this.statsTable.getFont().getStyle(),
                                     this.statsTable.getFont().getSize()));
    this.statsTable.setRowSelectionInterval(0, 0);
    this.statsTable.setEnabled(false);
    
    // Add the headers, then the table
    this.add(this.statsTable.getTableHeader(), BorderLayout.NORTH);
    this.add(this.statsTable, BorderLayout.CENTER);
    this.setVisible(true);
  }
  
  /**
   * Updates the count of pieces for a player.
   * 
   * @param player The int equal to the number of the player to update.
   * @param pieces The int equal to the number of pieces the player has.
   * 
   */
  
  public void updatePlayerPieces(int player, int pieces)
  {
    this.statsTableModel.setValueAt(pieces, player, this.statsTableModel.findColumn("Pieces"));    
  }
  
  /**
   * Updates the row selection for the table.
   * 
   */
  
  public void updateRowSelection()
  {
    int currentSelection = (this.statsTable.isRowSelected(0)) ? (0) : (1);
    int nextSelection = (currentSelection + 1) % 2;
    this.statsTable.setRowSelectionInterval(nextSelection, nextSelection);
  }
  
  /**
   * Resets the table.
   * 
   */
  
  public void reset()
  {
    if (this.parent instanceof OtelloPanel)
    {
      OtelloPanel valueSource = (OtelloPanel) this.parent;
      this.statsTableModel = new OtelloTableModel(valueSource.getPlayerZeroType(), 
                                                  valueSource.getPlayerZeroName(),
                                                  valueSource.getPlayerOneType(), 
                                                  valueSource.getPlayerOneName());
    }
    else
    {
      this.statsTableModel = new OtelloTableModel(PlayerType.GIRL, "Christine",
                                                  PlayerType.BOY, "Branden");      
    }
    
    this.statsTable.setModel(this.statsTableModel);
    this.statsTable.setRowSelectionInterval(0, 0);
  }
  
  /**
   * A model for the table displaying the round statistics.
   * 
   */
  private class OtelloTableModel extends AbstractTableModel
  {
    /**
     * The column headers.
     * 
     */
    private String[] headers;
    
    /**
     * The data stored in the table.
     * 
     */
    private Object[][] data;
    
    /**
     * Initializes the headers and data for this table using the given player information.
     * 
     * @param playerZeroType The PlayerType indicating the type for Player Zero.
     * @param playerZeroName The String containing the name of Player Zero.
     * @param playerOneType The PlayerType indicating the type for Player One.
     * @param playerOneName The String containing the name of Player One.
     * 
     */
    
    public OtelloTableModel(PlayerType playerZeroType, String playerZeroName,
                            PlayerType playerOneType, String playerOneName)
    {
      this.headers = new String[] {"Color", "Type", "Name", "Pieces"};
      this.data = new Object[][] {{ImageLoader.getImageIcon(this, "black-white_s_00.jpg"),
                                   ImageLoader.getImageIcon(this, getIconName(playerZeroType)), 
                                   playerZeroName, 2},
                                  {ImageLoader.getImageIcon(this, "white-black_s_00.jpg"),
                                   ImageLoader.getImageIcon(this, getIconName(playerOneType)), 
                                   playerOneName, 2}};
    }
    
    /**
     * Returns the number of columns in this OtelloTableModel.
     * 
     * @return The int equal to the number of columns that this OtelloTableModel contains.
     * 
     */
    
    @Override
    public int getColumnCount()
    {
      return this.headers.length;
    }

    /**
     * Returns the number of rows in the table.
     * 
     * @return The int equal to the number of rows in the table.
     * 
     */
    
    @Override
    public int getRowCount()
    {
      return this.data.length;
    }

    /**
     * Returns the value of a particular cell in this OtelloTableModel.
     * 
     * @param row The int equal to the row number of the cell to get.
     * @param column The int equal to the column number of the cell to get.
     * 
     * @return value The Object containing the value at the given row and column in this table.
     *               If the cell does not exist or has no value, then returns null.
     * 
     */
    
    @Override
    public Object getValueAt(int row, int column)
    {
      Object value = null;
      
      if ((0 <= row) && (row < this.getRowCount()) && 
          (0 <= column) && (column < this.getColumnCount()) && 
          (this.data[row][column] != null))
      {
        value = this.data[row][column];
      }      
      
      return value;
    }
    
    /**
     * Returns the column header for the parameter column number in this OtelloTableModel.
     * 
     * @param column The int equal to the column number for the desired column header.
     * 
     * @return header The String containing the column header for the given column number.
     *                If the number is not found, returns null.
     * 
     */
    
    @Override
    public String getColumnName(int column)
    {
      String header = null;
      
      if ((0 <= column) && (column < this.headers.length))
      {
        header = this.headers[column];
      }
        
      return header;
    }    

    /**
     * Returns the column number for the parameter column name in this OtelloTableModel.
     * 
     * @param header The String containing the column header to search for.
     * 
     * @return number The int equal to the column number for the parameter column header.
     *                If the header is not found, then returns -1.
     *                
     */
    
    @Override
    public int findColumn(String header)
    {
      int number = -1;
      
      for (int i = 0; i < this.headers.length; i++)
      {
        if (this.headers[i].equals(header))
        {
          number = i;
        }
      }
      
      return number;
    }

    /**
     * Returns the class type for the parameter column.
     * 
     * @param column The column number for the desired column class.
     * 
     * @return classType The class for the column number given in the parameters.
     * 
     */
    
    @Override
    public Class<?> getColumnClass(int column)
    {
      // If data does not exist yet, return type Object
      if (getValueAt(0, column) == null)
      {
        return Object.class;
      }
      else
      {
        return getValueAt(0, column).getClass();
      }
    }    
    
    /**
     * Reports all cells as uneditable.
     * Only the system itself may edit cells; the lack of a listener for cells
     * should ensure that the user cannot alter anything in that regard.
     * 
     * @param row The int equal to the row of the cell to check.
     * @param column The int equal to the column of the cell to check.
     * 
     * @return False for all cells.
     * 
     */
    
    @Override
    public boolean isCellEditable(int row, int column)
    {
      return false;
    }
    
    /**
     * Updates the value of a cell in this OtelloTableModel at the given parameters.
     *
     * @param value The Object containing the value to place in the cell.
     * @param row The int equal to the row of the cell to update.
     * @param column The int equal to the column of the cell to update.
     * 
     */
    
    @Override
    public void setValueAt(Object value, int row, int column)
    {
      // Updates the designated cell if the row and column are valid
      if (((0 <= row) && (row < getRowCount())) && 
          ((0 <= column) && (column < getColumnCount())))
      {
        this.data[row][column] = value;
        this.fireTableCellUpdated(row, column);
      }
    }
        
    /**
     * Returns the name of the icon file corresponding to the given player type.
     * 
     * @param type The PlayerType containing the type of the player to get an icon for.
     * 
     * @return iconFile A String containing the name of the image file for the player icon.
     * 
     */
    
    private String getIconName(PlayerType type)
    {
      String iconFile = "";
      
      switch (type)
      {        
        // For females
        case GIRL:
          iconFile = "girl_icon_s.gif";
          break;
          
        // For males
        case BOY:
          iconFile = "boy_icon_s.gif";
          break;

        // For computer players
        case COMPUTER:
          iconFile = "computer_icon_s.gif";
          break;

        default:
          break;
      }
      
      return iconFile;
    }
  }
}
